package unpackaged;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.junit.Test;
import com.zb.service.imp.middleware.MessageWrapper;

import java.net.InetSocketAddress;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.ReentrantLock;

//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = { "classpath:spring-cache.xml", "classpath:spring-captcha.xml", "classpath:spring-dao.xml", "classpath:spring-filter.xml", "classpath:spring-mvc.xml", "classpath:spring-service.xml",
//		"classpath:spring-shiro.xml", "classpath:spring-task.xml" })
public class SimulateClient
{
	private static Log log = LogFactory.getLog(SimulateClient.class);

	private static final int port = 8820;
	private static final String ip = "192.168.5.208";

	private static String chargerId = "5015300000000012";

	private final static char[] mChars = "0123456789ABCDEF".toCharArray();
	private final static String mHexStr = "0123456789ABCDEF";

	private final ExecutorService task = Executors.newCachedThreadPool();

	private Thread uploadChargingThread;

	private static String startChargingNo = "";

	private Boolean charging = false;

	//	@Test
	//	public void poolTest() throws InterruptedException
	//	{
	//		task.execute(new Runnable()
	//		{
	//			@Override
	//			public void run()
	//			{
	//				log.info(new Date());
	//				while (true)
	//					;
	//			}
	//		});
	//		Thread.sleep(10000);
	//
	//		ThreadPoolExecutor t;
	//
	//		task.shutdown();
	//
	//		log.info(task.isShutdown());
	//		log.info(task.isTerminated());
	//
	//		task.execute(new Runnable()
	//		{
	//			@Override
	//			public void run()
	//			{
	//				log.info("abc");
	//			}
	//		});
	//	}

	@Test
	public void start() throws Exception //Start() throws Exception
	{

		log.debug("Init");
		ChannelFactory factory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());

		ClientBootstrap bootstrap = new ClientBootstrap(factory);

		bootstrap.setPipelineFactory(new ChannelPipelineFactory()
		{
			public ChannelPipeline getPipeline()
			{
				ChannelPipeline pipeline = Channels.pipeline();
				pipeline.addLast("decoder", new CustomDecoder());
				//								pipeline.addLast("decoder", new LongConnectionSendMsgImpl.DzLongConnectionFrameDecoder());
				//				pipeline.addLast("encoder", new StringEncoder());
				//				pipeline.addLast("decoder", new LongConnectionSendMsgImpl.DzLongConnectionFrameDecoder());
				//				pipeline.addLast("encoder", new StringEncoder(Charset.forName("utf-8")));
				pipeline.addLast("handler", new ChannelUpstreamHandler());
				return pipeline;
			}
		});

		bootstrap.setOption("tcpNoDelay", true);
		bootstrap.setOption("keepAlive", true);
		bootstrap.setOption("connectTimeoutMillis", 10000l);

		log.info(String.format("try to create connection with ip: %1$s, port: %2$d", ip, port));
		ChannelFuture cf = bootstrap.connect(new InetSocketAddress(ip, port));
		cf.awaitUninterruptibly();
		Channel channel = null;
		if (cf.isSuccess())
		{
			channel = cf.getChannel();
			log.debug(String.format("Connection create successful, Channel Id: %1$d, ip: %2$s, port: %3$d", channel.getId(), ip, port));
			log.debug(channel);
		}
		else
		{
			log.error("Connection create failed");
			throw new Exception("Channel create failed");
		}

		final String login_msg = "681400A50001" + chargerId + "01002016050310345600010000323893559075123456788765432103110201";
		log.info("Login");
		log.info(login_msg);

		ChannelBuffer f = ChannelBuffers.buffer(120);
		f.writeBytes(hexStr2Bytes(login_msg));

		ChannelFuture ff = channel.write(f);
		ff.addListener(new ChannelFutureListener()
		{
			@Override
			public void operationComplete(ChannelFuture future) throws Exception
			{
				if (!future.isSuccess())
				{
					log.debug("Send message failed, message is: " + future.getChannel());
					return;
				}
				else
				{
					log.debug("Send message successful, message is: " + login_msg);
					return;
				}
			}
		});

		while (true)
			;

		//		byte b = 104;
		//		log.info(b);
	}

	public String byte2HexStr(byte[] b)
	{
		StringBuilder sb = new StringBuilder();
		for (int n = 0; n < b.length; n++)
		{
			sb.append(mChars[(b[n] & 0xFF) >> 4]);
			sb.append(mChars[b[n] & 0x0F]);
		}
		return sb.toString().trim().toUpperCase();
	}

	public class CustomDecoder extends OneToOneDecoder
	{

		@Override
		protected Object decode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception
		{
			ChannelBuffer buf = (ChannelBuffer) msg;
			String content = byte2HexStr(buf.array());
			//			log.info(content);

			return content;
			//
			//			buf.readBytes(4).array();
			//buf.array()
		}
	}

	public byte[] hexStr2Bytes(String src)
	{
		//处理值初始化
		int m = 0, n = 0;
		int iLen = src.length() / 2; //计算长度
		byte[] ret = new byte[iLen]; //分配存储空间

		for (int i = 0; i < iLen; i++)
		{
			m = i * 2 + 1;
			n = m + 1;
			ret[i] = (byte) (Integer.decode("0x" + src.substring(i * 2, m) + src.substring(m, n)) & 0xFF);
		}
		return ret;
	}

	private class ChannelUpstreamHandler extends SimpleChannelUpstreamHandler
	{
		@Override
		public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception
		{


			final String msg = (String) e.getMessage();
			final Channel channel = e.getChannel();
			log.debug("message received " + msg);

			final String type = msg.substring(6, 8);
			if ("11".equals(type) || "12".equals(type) || "13".equals(type) || "14".equals(type))
			{
				task.execute(new Runnable()
				{
					@Override
					public void run()
					{
						//68120013000132383000000000102100201605071800060001400000000188080028100000028533C3C421

						Random r = new Random();
						String responseCode = "000000";
						int x = r.nextInt(10);
						if ("13".equals(type) && x <= 9)
							responseCode = "FFFFFF";
						System.out.println(x);
						System.out.println(type);

						String serial = msg.substring(32, 50);

						String re_type = "5" + type.substring(1);
						String re = MessageFormat.format("680000{0}0001{1}11{2}00{3}123456789012345678", re_type, chargerId, responseCode, serial);
						log.debug(re);
						ChannelBuffer f = ChannelBuffers.buffer(100);
						f.writeBytes(hexStr2Bytes(re));

						channel.write(f);

						if ("13".equals(type))
						{
							charging = true;
							startChargingNo = serial;

							/*
							uploadChargingThread = new Thread(new Runnable()
							{
								@Override
								public void run()
								{
									while (charging)
									{
										log.info("upload charging status");
										synchronized (charging)
										{
											try
											{
												//68 2500 23 0001 chargerid 01 00 201604131427260033 startChargingNo usedQ 12345678 12345678 12345678 V I P SOC Time
												Random r = new Random();
												String usedQ = Integer.toString(r.nextInt(238) + 17, 16) + "000000";
												String V = Integer.toString(r.nextInt(238) + 17, 16) + "0000";
												String I = Integer.toString(r.nextInt(238) + 17, 16) + "0000";
												String P = Integer.toString(r.nextInt(238) + 17, 16) + "0000";

												String soc = Integer.toString(r.nextInt(83) + 17, 16);
												String remain_time = Integer.toString(r.nextInt(238) + 17, 16) + "00";

												log.info(MessageFormat
														.format("chargerId = {0}, startChargingNo = {1}, usedQ = {2}, V = {3}, I = {4}, P = {5}, soc = {6}, remain_time = {7}", chargerId, startChargingNo, usedQ, V, I, P,
																soc, remain_time));

												String send_msg = MessageFormat
														.format("682500230001{0}0100201604131427260033{1}{2}123456781234567812345678{3}{4}{5}{6}{7}", chargerId, startChargingNo, usedQ, V, I, P, soc, remain_time);
												log.debug(send_msg);
												ChannelBuffer f_send = ChannelBuffers.buffer(100);
												f_send.writeBytes(hexStr2Bytes(send_msg));
												channel.write(f_send);

												charging.wait(20000);
											}
											catch (InterruptedException e1)
											{
												log.debug(e1.getMessage(), e1);
											}
										}
									}
								}
							});
							uploadChargingThread.start();
							*/

						}
						else if ("14".equals(type))
						{
							try
							{
								synchronized (charging)
								{
									charging = false;
								}
								Thread.sleep(1000);
								log.info("upload bill");

								String chargingFee = Integer.toString(r.nextInt(238) + 17, 16) + "000000";
								String reservationFee = Integer.toString(r.nextInt(238) + 17, 16) + "000000";
								String serviceFee = Integer.toString(r.nextInt(238) + 17, 16) + "00";
								String q = Integer.toString(r.nextInt(238) + 17, 16) + "000000";

								int start_min = r.nextInt(200) - 200;
								int end_min = r.nextInt(200);
								SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
								Calendar c_start = Calendar.getInstance();
								c_start.set(Calendar.MINUTE, start_min);
								String start_time = sdf.format(c_start.getTime());
								Calendar c_end = Calendar.getInstance();
								c_end.set(Calendar.MINUTE, end_min);
								String end_time = sdf.format(c_end.getTime());

								log.info(MessageFormat
										.format("chargerId = {0}, reservationFee = {1}, chargingFee = {2}, serviceFee = {3}, startChargingNo = {4}, start_time = {5}, end_time = {6}, q = {7}", chargerId, reservationFee,
												chargingFee, serviceFee, startChargingNo, start_time, end_time, q));

								String send_msg = MessageFormat
										.format("684E00240001{0}030020160413142726003318808002810000002853{1}{2}{3}00{4}{5}{6}1234567887654321{7}5544332201FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", chargerId, reservationFee,
												chargingFee, serviceFee, startChargingNo, start_time, end_time, q);
								log.debug(send_msg);
								ChannelBuffer f_send = ChannelBuffers.buffer(210);
								f_send.writeBytes(hexStr2Bytes(send_msg));
								channel.write(f_send);

							}
							catch (InterruptedException e1)
							{
								log.error(e1.getMessage(), e1);
							}
						}
					}
				});
			}

		}

		@Override
		public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception
		{
			super.exceptionCaught(ctx, e);
			log.error(e.getChannel());

			log.error("Exception caught", e.getCause());
		}

	}

}
